From eb320ac26275e70a7e72e64f789284b0337bbbd9 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sat, 5 Nov 2005 11:26:29 +0100 Subject: [PATCH] This patch is to remove the pit_timer when the vmx domain is inactive to save HV external IRQ caused by ac_time and some cleanup for ioapic in HV. Thx,eddie Signed-off-by: Eddie Dong --- tools/ioemu/hw/pc.c | 3 -- tools/ioemu/target-i386-dm/Makefile | 3 +- tools/ioemu/target-i386-dm/helper2.c | 7 ---- xen/arch/x86/dm/i8259.c | 13 +++++++ xen/arch/x86/vmx.c | 25 +++++++++++- xen/arch/x86/vmx_intercept.c | 58 ++++++++++++++++++++-------- xen/arch/x86/vmx_io.c | 4 ++ xen/arch/x86/vmx_vlapic.c | 11 +++++- xen/arch/x86/vmx_vmcs.c | 1 + xen/include/asm-x86/vmx.h | 1 + xen/include/asm-x86/vmx_virpit.h | 20 ++++++++-- xen/include/asm-x86/vmx_vlapic.h | 3 +- xen/include/asm-x86/vmx_vmcs.h | 2 + xen/include/public/io/vmx_vlapic.h | 9 ----- xen/include/public/io/vmx_vpic.h | 1 + 15 files changed, 115 insertions(+), 46 deletions(-) diff --git a/tools/ioemu/hw/pc.c b/tools/ioemu/hw/pc.c index 97db4aaa94..5de7555045 100644 --- a/tools/ioemu/hw/pc.c +++ b/tools/ioemu/hw/pc.c @@ -547,9 +547,6 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, pci_pcnet_init(pci_bus, &nd_table[i]); } pci_piix3_ide_init(pci_bus, bs_table); -#ifdef APIC_SUPPORT - IOAPICInit(); -#endif } else { nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) diff --git a/tools/ioemu/target-i386-dm/Makefile b/tools/ioemu/target-i386-dm/Makefile index b97103486b..c05013f75c 100644 --- a/tools/ioemu/target-i386-dm/Makefile +++ b/tools/ioemu/target-i386-dm/Makefile @@ -187,7 +187,7 @@ endif ######################################################### -DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DAPIC_SUPPORT +DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS+=-lm -L../../libxc -lxenctrl ifndef CONFIG_USER_ONLY LIBS+=-lz @@ -245,7 +245,6 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o exec.o monitor.o osdep.o block.o readline.o pci.o console.o VL_OBJS+=block-cow.o block-qcow.o block-vmdk.o block-cloop.o aes.o -VL_OBJS+=ioapic.o #VL_OBJS+= block-cloop.o SOUND_HW = sb16.o diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c index c8039b42d0..6a97262715 100644 --- a/tools/ioemu/target-i386-dm/helper2.c +++ b/tools/ioemu/target-i386-dm/helper2.c @@ -456,17 +456,10 @@ int main_loop(void) #endif main_loop_wait(0); -#ifdef APIC_SUPPORT - ioapic_update_EOI(); -#endif tun_receive_handler(&rfds); if ( FD_ISSET(evtchn_fd, &rfds) ) { cpu_handle_ioreq(env); } -#ifdef APIC_SUPPORT - if (ioapic_has_intr()) - do_ioapic(); -#endif if (env->send_event) { struct ioctl_evtchn_notify notify; notify.port = ioreq_local_port; diff --git a/xen/arch/x86/dm/i8259.c b/xen/arch/x86/dm/i8259.c index ed3ffc8eaf..7d859f875e 100644 --- a/xen/arch/x86/dm/i8259.c +++ b/xen/arch/x86/dm/i8259.c @@ -525,3 +525,16 @@ int is_pit_irq(struct vcpu *v, int irq, int type) return (irq == pit_vec); } + +int is_irq_enabled(struct vcpu *v, int irq) +{ + struct vmx_virpic *vpic=&v->domain->arch.vmx_platform.vmx_pic; + + if ( irq & 8 ) { + return !( (1 << (irq&7)) & vpic->pics[1].imr); + } + else { + return !( (1 << irq) & vpic->pics[0].imr); + } +} + diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c index a7ba1fb3ce..fdf3423184 100644 --- a/xen/arch/x86/vmx.c +++ b/xen/arch/x86/vmx.c @@ -43,6 +43,8 @@ #endif #include #include +#include +#include int hvm_enabled; @@ -85,6 +87,8 @@ void vmx_final_setup_guest(struct vcpu *v) void vmx_relinquish_resources(struct vcpu *v) { + struct vmx_virpit *vpit; + if ( !VMX_DOMAIN(v) ) return; @@ -96,7 +100,12 @@ void vmx_relinquish_resources(struct vcpu *v) destroy_vmcs(&v->arch.arch_vmx); free_monitor_pagetable(v); - rem_ac_timer(&v->domain->arch.vmx_platform.vmx_pit.pit_timer); + vpit = &v->domain->arch.vmx_platform.vmx_pit; + if ( vpit->ticking && active_ac_timer(&(vpit->pit_timer)) ) + rem_ac_timer(&vpit->pit_timer); + if ( active_ac_timer(&v->arch.arch_vmx.hlt_timer) ) { + rem_ac_timer(&v->arch.arch_vmx.hlt_timer); + } if ( vmx_apic_support(v->domain) ) { rem_ac_timer( &(VLAPIC(v)->vlapic_timer) ); xfree( VLAPIC(v) ); @@ -1521,12 +1530,24 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs) (unsigned long)regs->edx); } -volatile unsigned long do_hlt_count; /* * Need to use this exit to reschedule */ void vmx_vmexit_do_hlt(void) { + struct vcpu *v=current; + struct vmx_virpit *vpit = &(v->domain->arch.vmx_platform.vmx_pit); + s_time_t next_pit=-1,next_wakeup; + + if ( !v->vcpu_id ) { + next_pit = get_pit_scheduled(v,vpit); + } + next_wakeup = get_apictime_scheduled(v); + if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 ) { + next_wakeup = next_pit; + } + if ( next_wakeup != - 1 ) + set_ac_timer(¤t->arch.arch_vmx.hlt_timer, next_wakeup); do_block(); } diff --git a/xen/arch/x86/vmx_intercept.c b/xen/arch/x86/vmx_intercept.c index c21ad44fdb..d452f7b792 100644 --- a/xen/arch/x86/vmx_intercept.c +++ b/xen/arch/x86/vmx_intercept.c @@ -317,27 +317,51 @@ int intercept_pit_io(ioreq_t *p) return 0; } -/* hooks function for the PIT initialization response iopacket */ -static void pit_timer_fn(void *data) +/* hooks function for the HLT instruction emulation wakeup */ +void hlt_timer_fn(void *data) +{ + struct vcpu *v = data; + + evtchn_set_pending(v, iopacket_port(v->domain)); +} + +static __inline__ void missed_ticks(struct vmx_virpit*vpit) { - struct vmx_virpit *vpit = data; - s_time_t next; int missed_ticks; missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period; - - /* Set the pending intr bit, and send evtchn notification to myself. */ - vpit->pending_intr_nr++; /* already set, then count the pending intr */ - evtchn_set_pending(vpit->v, iopacket_port(vpit->v->domain)); - - /* pick up missed timer tick */ if ( missed_ticks > 0 ) { vpit->pending_intr_nr += missed_ticks; vpit->scheduled += missed_ticks * vpit->period; } - next = vpit->scheduled + vpit->period; - set_ac_timer(&vpit->pit_timer, next); - vpit->scheduled = next; +} + +/* hooks function for the PIT when the guest is active */ +static void pit_timer_fn(void *data) +{ + struct vcpu *v = data; + struct vmx_virpit *vpit = &(v->domain->arch.vmx_platform.vmx_pit); + + /* pick up missed timer tick */ + missed_ticks(vpit); + + vpit->pending_intr_nr++; + if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) { + vpit->scheduled += vpit->period; + set_ac_timer(&vpit->pit_timer, vpit->scheduled); + } +} + +void pickup_deactive_ticks(struct vmx_virpit *vpit) +{ + + if ( !active_ac_timer(&(vpit->pit_timer)) ) { + /* pick up missed timer tick */ + missed_ticks(vpit); + + vpit->scheduled += vpit->period; + set_ac_timer(&vpit->pit_timer, vpit->scheduled); + } } /* Only some PIT operations such as load init counter need a hypervisor hook. @@ -359,8 +383,10 @@ void vmx_hooks_assist(struct vcpu *v) reinit = 1; } - else - init_ac_timer(&vpit->pit_timer, pit_timer_fn, vpit, v->processor); + else { + init_ac_timer(&vpit->pit_timer, pit_timer_fn, v, v->processor); + vpit->ticking = 1; + } /* init count for this channel */ vpit->init_val = (p->u.data & 0xFFFF) ; @@ -397,8 +423,6 @@ void vmx_hooks_assist(struct vcpu *v) break; } - vpit->v = v; - vpit->scheduled = NOW() + vpit->period; set_ac_timer(&vpit->pit_timer, vpit->scheduled); diff --git a/xen/arch/x86/vmx_io.c b/xen/arch/x86/vmx_io.c index 33d4c7290c..5b879bd52e 100644 --- a/xen/arch/x86/vmx_io.c +++ b/xen/arch/x86/vmx_io.c @@ -931,6 +931,7 @@ asmlinkage void vmx_intr_assist(void) void vmx_do_resume(struct vcpu *v) { + struct vmx_virpit *vpit = &(v->domain->arch.vmx_platform.vmx_pit); vmx_stts(); if (event_pending(v)) { @@ -939,6 +940,9 @@ void vmx_do_resume(struct vcpu *v) if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) vmx_wait_io(); } + /* pick up the elapsed PIT ticks and re-enable pit_timer */ + if ( vpit->ticking ) + pickup_deactive_ticks(vpit); /* We can't resume the guest if we're waiting on I/O */ ASSERT(!test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)); diff --git a/xen/arch/x86/vmx_vlapic.c b/xen/arch/x86/vmx_vlapic.c index 80f372f282..4d45fcd3e6 100644 --- a/xen/arch/x86/vmx_vlapic.c +++ b/xen/arch/x86/vmx_vlapic.c @@ -60,11 +60,20 @@ int vlapic_find_highest_irr(struct vlapic *vlapic) return result; } -inline int vmx_apic_support(struct domain *d) +int vmx_apic_support(struct domain *d) { return d->arch.vmx_platform.lapic_enable; } +s_time_t get_apictime_scheduled(struct vcpu *v) +{ + struct vlapic *vlapic = VLAPIC(v); + + if ( !vmx_apic_support(v->domain) || !vlapic_lvt_timer_enabled(vlapic) ) + return -1; + return vlapic->vlapic_timer.expires; +} + int vlapic_find_highest_isr(struct vlapic *vlapic) { int result; diff --git a/xen/arch/x86/vmx_vmcs.c b/xen/arch/x86/vmx_vmcs.c index 97d66e2ef7..abf3684160 100644 --- a/xen/arch/x86/vmx_vmcs.c +++ b/xen/arch/x86/vmx_vmcs.c @@ -321,6 +321,7 @@ static void vmx_do_launch(struct vcpu *v) vlapic_init(v); vmx_set_host_env(v); + init_ac_timer(&v->arch.arch_vmx.hlt_timer, hlt_timer_fn, v, v->processor); error |= __vmwrite(GUEST_LDTR_SELECTOR, 0); error |= __vmwrite(GUEST_LDTR_BASE, 0); diff --git a/xen/include/asm-x86/vmx.h b/xen/include/asm-x86/vmx.h index 445c24bb59..771ac68ef4 100644 --- a/xen/include/asm-x86/vmx.h +++ b/xen/include/asm-x86/vmx.h @@ -530,5 +530,6 @@ void store_cpu_user_regs(struct cpu_user_regs *regs); enum { VMX_COPY_IN = 0, VMX_COPY_OUT }; int vmx_copy(void *buf, unsigned long laddr, int size, int dir); +void pickup_deactive_ticks(struct vmx_virpit *vpit); #endif /* __ASM_X86_VMX_H__ */ diff --git a/xen/include/asm-x86/vmx_virpit.h b/xen/include/asm-x86/vmx_virpit.h index 9539682d94..fad07a9847 100644 --- a/xen/include/asm-x86/vmx_virpit.h +++ b/xen/include/asm-x86/vmx_virpit.h @@ -8,6 +8,7 @@ #include #include #include +#include #define PIT_FREQ 1193181 @@ -18,14 +19,15 @@ struct vmx_virpit { /* for simulation of counter 0 in mode 2*/ - u32 period; /* pit frequency in ns */ u64 period_cycles; /* pit frequency in cpu cycles */ + u64 inject_point; /* the time inject virt intr */ s_time_t scheduled; /* scheduled timer interrupt */ + struct ac_timer pit_timer; /* periodic timer for mode 2*/ unsigned int channel; /* the pit channel, counter 0~2 */ unsigned int pending_intr_nr; /* the couner for pending timer interrupts */ - u64 inject_point; /* the time inject virt intr */ - struct ac_timer pit_timer; /* periodic timer for mode 2*/ + u32 period; /* pit frequency in ns */ int first_injected; /* flag to prevent shadow window */ + int ticking; /* indicating it is ticking */ /* virtual PIT state for handle related I/O */ int read_state; @@ -34,10 +36,20 @@ struct vmx_virpit { unsigned int count; /* the 16 bit channel count */ unsigned int init_val; /* the init value for the counter */ - struct vcpu *v; }; /* to hook the ioreq packet to get the PIT initializaiton info */ extern void vmx_hooks_assist(struct vcpu *v); +static __inline__ s_time_t get_pit_scheduled( + struct vcpu *v, + struct vmx_virpit *vpit) +{ + if ( is_irq_enabled(v, 0) ) { + return vpit->scheduled; + } + else + return -1; +} + #endif /* _VMX_VIRPIT_H_ */ diff --git a/xen/include/asm-x86/vmx_vlapic.h b/xen/include/asm-x86/vmx_vlapic.h index 53dee225b4..c8b4dde3a7 100644 --- a/xen/include/asm-x86/vmx_vlapic.h +++ b/xen/include/asm-x86/vmx_vlapic.h @@ -239,7 +239,8 @@ struct vlapic* apic_round_robin(struct domain *d, uint8_t dest_mode, uint8_t vector, uint32_t bitmap); - +s_time_t get_apictime_scheduled(struct vcpu *v); int vmx_apic_support(struct domain *d); #endif /* VMX_VLAPIC_H */ + diff --git a/xen/include/asm-x86/vmx_vmcs.h b/xen/include/asm-x86/vmx_vmcs.h index 2d366ef7a5..769fe555bb 100644 --- a/xen/include/asm-x86/vmx_vmcs.h +++ b/xen/include/asm-x86/vmx_vmcs.h @@ -99,6 +99,7 @@ struct arch_vmx_struct { void *io_bitmap_a, *io_bitmap_b; struct vlapic *vlapic; u64 tsc_offset; + struct ac_timer hlt_timer; /* hlt ins emulation wakeup timer */ }; #define vmx_schedule_tail(next) \ @@ -116,6 +117,7 @@ struct vmcs_struct *alloc_vmcs(void); int modify_vmcs(struct arch_vmx_struct *arch_vmx, struct cpu_user_regs *regs); void destroy_vmcs(struct arch_vmx_struct *arch_vmx); +void hlt_timer_fn(void *data); #define VMCS_USE_HOST_ENV 1 #define VMCS_USE_SEPARATE_ENV 0 diff --git a/xen/include/public/io/vmx_vlapic.h b/xen/include/public/io/vmx_vlapic.h index 5a8162b2e1..f63a9aaf16 100644 --- a/xen/include/public/io/vmx_vlapic.h +++ b/xen/include/public/io/vmx_vlapic.h @@ -28,14 +28,6 @@ #define VLAPIC_INT_COUNT (VLOCAL_APIC_MAX_INTS/(BITS_PER_BYTE * sizeof(uint64_t))) #define VLAPIC_INT_COUNT_32 (VLOCAL_APIC_MAX_INTS/(BITS_PER_BYTE * sizeof(uint32_t))) -struct vapic_bus_message{ - uint8_t deliv_mode:4; /* deliver mode, including fixed, LPRI, etc */ - uint8_t level:1; /* level or edge */ - uint8_t trig_mod:1; /* assert or disassert */ - uint8_t reserved:2; - uint8_t vector; -}; - typedef struct { /* interrupt for PIC and ext type IOAPIC interrupt */ uint64_t vl_ext_intr[VLAPIC_INT_COUNT]; @@ -51,7 +43,6 @@ typedef struct { uint32_t vl_arb_id; uint32_t vl_state; uint32_t apic_msg_count; - struct vapic_bus_message vl_apic_msg[24]; } vlapic_info; #endif /* _VMX_VLAPIC_H_ */ diff --git a/xen/include/public/io/vmx_vpic.h b/xen/include/public/io/vmx_vpic.h index e567c63400..256ac87ec5 100644 --- a/xen/include/public/io/vmx_vpic.h +++ b/xen/include/public/io/vmx_vpic.h @@ -77,6 +77,7 @@ uint32_t pic_intack_read(struct vmx_virpic *s); void register_pic_io_hook (void); int cpu_get_pic_interrupt(struct vcpu *v, int *type); int is_pit_irq(struct vcpu *v, int irq, int type); +int is_irq_enabled(struct vcpu *v, int irq); void do_pic_irqs (struct vmx_virpic *s, uint16_t irqs); void do_pic_irqs_clear (struct vmx_virpic *s, uint16_t irqs); -- 2.30.2